package com.weiyun.shortlink.admin.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.weiyun.shortlink.admin.biz.user.UserContext;
import com.weiyun.shortlink.admin.common.convention.exception.ClientException;
import com.weiyun.shortlink.admin.common.convention.result.Result;
import com.weiyun.shortlink.admin.dao.entity.GroupDao;
import com.weiyun.shortlink.admin.dao.mapper.GroupMapper;
import com.weiyun.shortlink.admin.dto.req.ShortLinkGroupSortReqDto;
import com.weiyun.shortlink.admin.dto.req.ShortLinkGroupUpdateDto;
import com.weiyun.shortlink.admin.dto.resp.ShortLinkGroupResponseDto;
import com.weiyun.shortlink.admin.remote.ShortLinkActualRemoteService;
import com.weiyun.shortlink.admin.remote.ShortLinkRemoteService;
import com.weiyun.shortlink.admin.remote.dto.resp.ShortLinkQueryCountRespDto;
import com.weiyun.shortlink.admin.service.GroupService;
import com.weiyun.shortlink.admin.toolkit.RandomGenerator;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Objects;
import java.util.Optional;

import static com.weiyun.shortlink.admin.common.constant.RedisCacheConstant.LOCK_GROUP_CREATE_KEY;

/***
 *   @Author:weiyun
 *
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class GroupServiceImpl extends ServiceImpl<GroupMapper, GroupDao> implements GroupService {
    ShortLinkRemoteService shortLinkRemoteService = new ShortLinkRemoteService() {
    };
    private final ShortLinkActualRemoteService shortLinkActualRemoteService;
    private final RedissonClient redissonClient;
    @Value("${short-link.group.max-number}")
    private Integer maxNumber;
    @Override
    public void save(String groupName) {
        this.save(UserContext.getUsername(),groupName);
    }

    @Override
    public void save(String username, String groupName) {
        RLock lock = redissonClient.getLock(String.format(LOCK_GROUP_CREATE_KEY, username));
        lock.lock();
        try {
            LambdaQueryWrapper<GroupDao> wrapper = Wrappers.lambdaQuery(GroupDao.class)
                    .eq(GroupDao::getUsername, username)
                    .eq(GroupDao::getDelFlag, 0);
            List<GroupDao> groupDaos = baseMapper.selectList(wrapper);
            if(CollUtil.isNotEmpty(groupDaos) && groupDaos.size() == maxNumber){
                throw new ClientException(String.format("已超出最大分组数量：%d",maxNumber));
            }
            String gid;
            while (true) {
                gid = RandomGenerator.generateRandomString();
                if (hasGid(username, gid)) {
                    break;
                }

            }
            GroupDao groupDao = GroupDao.builder()
                    .gid(RandomGenerator.generateRandomString())
                    .sortOrder(0)
                    .username(username)
                    .name(groupName)
                    .build();
            baseMapper.insert(groupDao);
        }finally {
            lock.unlock();
        }
        }

    @Override
    public List<ShortLinkGroupResponseDto> listGroup() {
        LambdaQueryWrapper<GroupDao> wrapper = Wrappers.lambdaQuery(GroupDao.class)
                .eq(GroupDao::getUsername, UserContext.getUsername())
                .eq(GroupDao::getDelFlag,0)
                .orderByDesc(GroupDao::getSortOrder, GroupDao::getUpdateTime);
        List<GroupDao> groupDaoList = baseMapper.selectList(wrapper);
        Result<List<ShortLinkQueryCountRespDto>> listResult = shortLinkActualRemoteService
                .listShortLinkGroupCount(groupDaoList.stream().map(GroupDao::getGid).toList());
        List<ShortLinkGroupResponseDto> shortLinkGroupResponseDtos = BeanUtil.copyToList(groupDaoList, ShortLinkGroupResponseDto.class);
        shortLinkGroupResponseDtos.forEach(each -> {
            Optional<ShortLinkQueryCountRespDto> first = listResult.getData().stream()
                    .filter(item -> Objects.equals(item.getGid(), each.getGid()))
                    .findFirst();
            first.ifPresent(item ->each.setShortLinkCount(first.get().getShortLinkCount()));
        });
        return shortLinkGroupResponseDtos;
    }

    @Override
    public void updateGroup(ShortLinkGroupUpdateDto shortLinkGroupUpdateDto) {
        LambdaUpdateWrapper<GroupDao> wrapper = Wrappers.lambdaUpdate(GroupDao.class)
                .eq(GroupDao::getUsername, UserContext.getUsername())
                .eq(GroupDao::getGid, shortLinkGroupUpdateDto.getGid())
                .eq(GroupDao::getDelFlag, 0);
        GroupDao groupDao = new GroupDao();
        groupDao.setName(shortLinkGroupUpdateDto.getName());
        baseMapper.update(groupDao,wrapper);
    }

    @Override
    public void deleteGroup(String gid) {
        LambdaUpdateWrapper<GroupDao> wrapper = Wrappers.lambdaUpdate(GroupDao.class)
                .eq(GroupDao::getUsername, UserContext.getUsername())
                .eq(GroupDao::getGid,gid)
                .eq(GroupDao::getDelFlag, 0);
        GroupDao groupDao = new GroupDao();
        groupDao.setDelFlag(1);
        baseMapper.update(groupDao,wrapper);
    }

    @Override
    public void sortGroup(List<ShortLinkGroupSortReqDto> shortLinkGroupSortReqDto) {
        shortLinkGroupSortReqDto.forEach(each ->{
            GroupDao groupDao = GroupDao.builder()
                    .sortOrder(each.getSortOrder())
                    .build();
            LambdaUpdateWrapper<GroupDao> wrapper = Wrappers.lambdaUpdate(GroupDao.class)
                    .eq(GroupDao::getUsername, UserContext.getUsername())
                    .eq(GroupDao::getGid, each.getGid())
                    .eq(GroupDao::getDelFlag, 0);
            baseMapper.update(groupDao,wrapper);
        });
    }

    private boolean hasGid(String username,String gid) {
//        String gid = RandomGenerator.generateRandomString();
        LambdaQueryWrapper<GroupDao> wrapper = Wrappers.lambdaQuery(GroupDao.class)
                .eq(GroupDao::getGid, gid)
                .eq(GroupDao::getUsername, Optional.ofNullable(username).orElse(UserContext.getUsername()));
        GroupDao hasGroupFlag = baseMapper.selectOne(wrapper);
        return hasGroupFlag == null;
    }

}
